package generator.gridgain;

import java.io.File;

import javax.xml.xpath.XPathConstants;

import generator.utils.java2xml.DocumentModifier;
import generator.utils.TransformDocs;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * Es la clase encargada de la generación de un Wrapper que aloja el resultado de la ejecución de un trabajo que fue enviado al grid.<BR> Dicho wrapper contiene sólo dos métodos y un atributo: el constructor de la clase, un getter del resultado que se setea a la instancia de la clase mediante el contructor y un atributo que representa el resultado. La clase es generada partiendo del template GridExecutorResult.xml (alojado en el directorio "conf" del proyecto).<BR> El nombre del wrapper generado es una combinación del nombre de la clase que contiene el método a gridificar junto con el nombre del método a gridificar propiamente dicho más un sufijo compuesto por las iniciales GER que corresponden a Grid Executor Result.
 */
public class GridExecutorResultBuilder extends DocumentModifier implements Buildable{
	
	
	/**
	 * Es la ruta del archivo template que se utilizará para construir el documento que representa la clase GER
	 * @uml.property  name="xmlTemplate"
	 */
	private String xmlTemplate = new String("conf//gridgainGen//GridExecutorResult.xml");
	
	
	/**
	 * Representa la signatura del método que se pretende gridificar. De este se extrae información tal como el tipo asociado al atributo result de la clase GER y el nombre del método que formará parte del nombre de la clase GER.
	 * @uml.property  name="methodToGridify"
	 */
	private org.w3c.dom.Element methodToGridify = null;
	
	
	/**
	 * Documento que representa la clase a gridificar que contiene el método a gridificar. De ella  se extrae información tal como el paquete al que pertenecer la clase y el nombre de la misma, Dicho documento es el que representa la clase del usuario que contiene las convenciones JGrim
	 * @uml.property  name="classToGridify"
	 */
	private org.w3c.dom.Document classToGridify = null;
		
	
	/**Constructor vacío de un GridExecutorResultBuilder.*/	 
	public GridExecutorResultBuilder(){				
	}
	
	/**Constructor de la clase GridExecutorResultBuilder
	 * @param classToGridify
	 * 			Documento que representa la clase que contiene el método a gridificar. De esta se extrae información
	 * 			tal como el paquete	al que pertenece la clase y el nombre de la misma.
	 * 			Dicho documento es el que representa la clase del usuario que contiene las convenciones JGrim
	 * @param methodToGridify
	 * 			Representa la signatura del método que se pretende gridificar del la cual se extrae
	 * 			información tal como el tipo que se asociará al atributo result de la clase GER y el
	 * 			nombre del método que servirá para la formación del	nombre de la clase GER.
	 * */
	public GridExecutorResultBuilder(org.w3c.dom.Document classToGridify, org.w3c.dom.Element methodToGridify){
		super();
		this.classToGridify = classToGridify;
		this.methodToGridify = methodToGridify;
	}
	
	/**
	 * @return        un org.w3c.dom.Element que representa la signatura del método a gridificar que será empleada  para la generación de la clase GER
	 * @uml.property  name="methodToGridify"
	 */
	public org.w3c.dom.Element getMethodToGridify() {
		return methodToGridify;
	}
	
	/**
	 * Setea la signatura del método sobre la que se basará la generación de la clase GER.
	 * @param methodToGridify        representa la signatura del método de la cual se extraerá el nombre del método y tipo de objeto  retornado, datos necesarios en la construcción de la clase GER
	 * @uml.property  name="methodToGridify"
	 */
	public void setMethodToGridify(org.w3c.dom.Element methodToGridify) {
		this.methodToGridify = methodToGridify;
	}

	/**
	 * @return org.w3c.dom.Document que representa la clase que contiene el método a gridificar la cual resulta necesaria para la generación de la clase GER
	 * @uml.property  name="classToGridify"
	 */
	public org.w3c.dom.Document getClassToGridify() {
		return classToGridify;
	}

	/**
	 * Setea la clase que contiene el método a gridificar la cual será necesaria en la generación de la clase GER.
	 * @param classToGridify        representa la clase que contiene el método a gridificar de la cual se extraerá el  paquete al que pertenece y su nombre necesarios para la construcción de la clase GER
	 * @uml.property  name="classToGridify"
	 */
	public void setClassToGridify(org.w3c.dom.Document classToGridify) {
		this.classToGridify = classToGridify;
	}

	/**
	 * @return la ruta del archivo template que se utiliza para construir el documento que representa  la clase GER
	 * @uml.property  name="xmlTemplate"
	 */
	public String getXmlTemplate() {
		return xmlTemplate;
	}

	/**
	 * @param templateFilepath
	 *         ruta que especifíca el lugar donde se halla el template que se utilizará para la construcción  de la clase GER. El template es un archivo xml
	 * @uml.property  name="xmlTemplate"
	 */
	public void setXmlTemplate(String templateFilepath){
		xmlTemplate = templateFilepath;		
	}
	
	
	/**Construye el documento que representa la clase GER (Grid Executor Result) basándose en el archivo indicado
	 * por el atributo {@link xmlTemplate}. La clase generada pertenecerá al mismo paquete que la clase
	 * {@link classToGridify}.
	 * El tipo del atributo <I>result</I> de la clase GER es extraido del atributo {@link methodToGridify}.
	 * Por todo esto, es necesario que antes de la invocación los atributos mencionados se 
	 * encuentren seteados con valores distintos a null. 
     * */
    public org.w3c.dom.Document build(){
                       
            Document GERDoc = TransformDocs.xmlToDom(new File(xmlTemplate));
            System.out.println("********* Generando clase GridExecutorResult **********");
            
            if (methodToGridify != null && classToGridify != null){
	            try{
		        
		                   
		            System.out.print("[INFO] seteo del paquete al que pertenece... ");            
		            this.setPackage(classToGridify, GERDoc);
		            System.out.println();
		           
		            System.out.print("[INFO] seteo del tipo de resultado que aloja... ");
		            Element sourceType = (Element)(methodToGridify.getElementsByTagName(TYPE).item(FIRST));
		            Element typeAtt = (Element)xpath.evaluate("/"+CLASSFILENAME+"/"+CLASS+"/"+ATTRIBUTE+"[@name=\"result\"]/"+TYPE+"[1]", GERDoc, XPathConstants.NODE); 
		            this.copyAttributes(sourceType, typeAtt, true);
		            System.out.println();
		           
		            System.out.print("[INFO] seteo del tipo del parámetro del constructor... ");            
		            Element typeConstr = (Element)xpath.evaluate("/"+CLASSFILENAME+"/"+CLASS+"/"+CONSTRUCTOR+"/"+ALLPARAMS+"/"+PARAM+"/"+TYPE, GERDoc, XPathConstants.NODE);
		            this.copyAttributes(sourceType, typeConstr, true);
		            System.out.println();
		           
		            System.out.print("[INFO] seteo del tipo del valor de retorno del método getResult... ");
		            Element typeReturn = (Element)xpath.evaluate("/"+CLASSFILENAME+"/"+CLASS+"/"+METHOD+"[@name=\"getResult\"]/"+TYPE, GERDoc, XPathConstants.NODE);
		            this.copyAttributes(sourceType, typeReturn, true);	            
		            System.out.println();
		            
		            System.out.print("[INFO] seteo de imports... ");
		            this.cloneImports(classToGridify, GERDoc);
		            System.out.println("finalizado");
		            
		            System.out.print("[INFO] seteo del nombre de clase... ");
		            String prefix = (String)xpath.evaluate("//"+CLASS+"/@name", classToGridify, XPathConstants.STRING);
		            prefix += "_"+(String)xpath.evaluate("@name", methodToGridify, XPathConstants.STRING);
		            this.setClassName(prefix+"GER", GERDoc);
		            System.out.println(prefix+"GER");
		            
	            }
	            catch(Exception e){
	            	System.out.println("[ERR] error durante la generación de clase Grid Executor Result");
	            	e.printStackTrace();
	            }
            }
            else
            	System.err.println("[ERR] falló creación de GridExecutorResult: clase o método a gridificar no seteados");
            return GERDoc;
    }		

}
